package displayboardinfo.services;

import java.util.Iterator;

import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.xml.bind.JAXBElement;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;

import com.sun.jersey.api.client.ClientResponse.Status;

import displayboardinfo.entities.Room;
import displayboardinfo.messages.ListRoomsRes;

/**
 * Klasa odpowiedzialna za wystawianie usług związanych z obsługą gabinetów.
 * 
 * @author Artur Jaworski
 */
@Path("/rooms")
public class RoomsServices {
	/**
	 * Usługa listowania gabinetów w systemie.
	 * Usługa dostępna jest na serwerze pod adresem /rooms/list używając metody GET.
	 * 
	 * @return lista gabinetów w systemie.
	 */
	@SuppressWarnings({ "deprecation", "rawtypes" })
	@Path("/list")
	@GET
	@Produces(MediaType.APPLICATION_XML)
	public ListRoomsRes list() {
		ListRoomsRes response = new ListRoomsRes();
		SessionFactory sf = new Configuration().configure().buildSessionFactory();
		Session session = sf.openSession();

		Query query = session
				.createQuery("from Room as r order by r.number");
		for (Iterator it = query.iterate(); it.hasNext();) {
			Object item = it.next();

			Room room = (Room) item;
			response.addRoom(room);
		}
		session.close();
		sf.close();
		return response;

	}
	
	/**
	 * Usługa dodania nowego gabinetu do bazy.
	 * Usługa dostępna jest na serwerze pod adresem /rooms/add używając metody POST.
	 * Usługa zwraca kod 200 [OK] gdy wywołanie się powiedzie lub kod 406 [NOT ACCEPTABLE] gdy wystąpi błąd (drugi gabinet o tym samym numerze, błąd serwera).
	 * Przy wystąpieniu błędu do odpowiedzi dołączany jest krótki opis przyczyny błędu.
	 * 
	 * @param roomJaxb obiekt reprezentujący gabinet dodawany do systemu, w formie koperty XML
	 * @return obiekt stworzonego gabinetu z uzupełnionym ID nadanym przez bazę danych
	 */
	@SuppressWarnings("deprecation")
	@Path("/add")
	@POST
	@Consumes(MediaType.APPLICATION_XML)
	public Room add(JAXBElement<Room> roomJaxb) {
		Room room = roomJaxb.getValue();
		
		SessionFactory sf = new Configuration().configure().buildSessionFactory();
		Session session = sf.openSession();
		Transaction transaction = session.beginTransaction();
		try {
			session.save(room);
			transaction.commit();
			return room;
		} catch (Exception e) {
			transaction.rollback();
			throw new WebApplicationException(Response.status(Status.NOT_ACCEPTABLE).entity("Nieznany błąd").type(MediaType.TEXT_PLAIN).build());
		} finally {
			session.close();
			sf.close();
		}
	}
	
	/**
	 * Usługa modyfikacji istniejącego gabinetu.
	 * Usługa dostępna jest na serwerze pod adresem /rooms/modify używając metody POST.
	 * Usługa zwraca kod 200 [OK] gdy wywołanie się powiedzie lub kod 406 [NOT ACCEPTABLE] gdy wystąpi błąd (drugi gabinet o tym samym numerze, błąd serwera).
	 * Przy wystąpieniu błędu do odpowiedzi dołączany jest krótki opis przyczyny błędu.
	 * 
	 * @param roomJaxb obiekt reprezentujący modyfikowany gabinet, w formie koperty XML
	 * @return pusta odpowiedź, zawierająca kod i komunikat o błędzie w przypadku niepowodzenia
	 */
	@SuppressWarnings("deprecation")
	@Path("/modify")
	@POST
	@Consumes(MediaType.APPLICATION_XML)
	public Response modify(JAXBElement<Room> roomJaxb) {
		Room room = roomJaxb.getValue();
		
		SessionFactory sf = new Configuration().configure().buildSessionFactory();
		Session session = sf.openSession();
		Transaction transaction = session.beginTransaction();
		try {
			session.update(room);
			transaction.commit();
			return Response.ok().build();
		} catch (Exception e) {
			transaction.rollback();
			throw new WebApplicationException(Response.status(Status.NOT_ACCEPTABLE).entity("Nieznany błąd").type(MediaType.TEXT_PLAIN).build());
		} finally {
			session.close();
			sf.close();
		}

	}
	
	/**
	 * Usługa usunięcia istniejącego gabinetu.
	 * Usługa dostępna jest na serwerze pod adresem /rooms/delete używając metody POST.
	 * Usługa zwraca kod 200 [OK] gdy wywołanie się powiedzie lub kod 406 [NOT ACCEPTABLE] gdy wystąpi błąd (nieistniejący gabinet, błąd serwera).
	 * Przy wystąpieniu błędu do odpowiedzi dołączany jest krótki opis przyczyny błędu.
	 * 
	 * @param roomJaxb obiekt reprezentujący gabinet usuwany z systemu, w formie koperty XML
	 * @return pusta odpowiedź, zawierająca kod i komunikat o błędzie w przypadku niepowodzenia
	 */
	@SuppressWarnings("deprecation")
	@Path("/delete")
	@POST
	@Consumes(MediaType.APPLICATION_XML)
	public Response delete(JAXBElement<Room> roomJaxb) {
		Room room = roomJaxb.getValue();

		SessionFactory sf = new Configuration().configure().buildSessionFactory();
		Session session = sf.openSession();
		Transaction transaction = session.beginTransaction();
		try {
			session.delete(room);
			transaction.commit();
			return Response.ok().build();
		} catch (Exception e) {
			transaction.rollback();
			throw new WebApplicationException(Response.status(Status.NOT_ACCEPTABLE).entity("Nieznany błąd").type(MediaType.TEXT_PLAIN).build());
		} finally {
			session.close();
			sf.close();
		}

	}
}
